﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Security.Cryptography.X509Certificates;
using System.Runtime.InteropServices;
using System.Net.Mail;
using CDO;
using ADODB;
using SEO;

namespace NHINDirect
{
    /// <summary>
    /// Interfaces with the free SMTP Service built into Win2k8 and Win2k3 - and makes it NHIN-D capaable
    /// 
    /// This object is used to interface with COM components - both SMTP server and VBScript/JScript based. 
    /// So it adds constructs to enable those usage patterns
    /// Exceptions are caught and success failure returned instead
    /// </summary>
    [ComVisible(true)]
    [ClassInterface(ClassInterfaceType.AutoDual)]
    [Guid("E48C52D5-1A7C-4e66-B8AE-2B08E4505829")]
    public class SmtpAgent : ISMTPOnArrival, IEventIsCacheable
    {    
        //
        // It is possible that this COM object will get created for every request - and is therefore meant to be very lightweight. 
        // Therefore, internally, we maintain a singleton of the actual agent and just proxy calls. 
        //
        static Dictionary<string, SmtpAgentImpl> s_agents = new Dictionary<string,SmtpAgentImpl>(StringComparer.OrdinalIgnoreCase);
        
        SmtpAgentImpl m_agent;
        
        public SmtpAgent()
        {
               
        }
        
        internal SmtpAgentImpl Agent
        {
            get
            {
                if (m_agent == null)
                {
                    throw new InvalidOperationException("Not initialized");
                }
            
                return m_agent;
            }
        }

        public void IsCacheable()
        {
        }
        
        public bool Init(string domain, string logFolderPath)
        {            
            if (m_agent == null || !this.IsAgentInitialized(m_agent, domain, logFolderPath))
            {
                m_agent = this.EnsureAgent(domain, logFolderPath);
            }
            
            return (m_agent != null);
        }
        
        SmtpAgentImpl EnsureAgent(string domain, string logFolderPath)
        {
            lock (s_agents)
            {
                SmtpAgentImpl agent = null;
                if (s_agents.TryGetValue(domain, out agent) && !this.IsAgentInitialized(agent, domain, logFolderPath))
                {
                    agent = null;
                }
                
                if (agent == null)
                {
                    try
                    {
                        agent = new SmtpAgentImpl();
                        agent.Init(domain, logFolderPath);
                        s_agents[domain] = agent;
                    }
                    catch
                    {
                    }
                }
                
                return agent;
            }
        }
        
        public void OnArrival(CDO.Message msg, ref CdoEventStatus eventStatus)
        {
            this.ProcessMessage(msg);            
            eventStatus = CdoEventStatus.cdoRunNextSink;
        }
        
        public int ClassifyMessage(CDO.Message cdoMessage)
        {
            return (int) this.Agent.ClassifyMessage(cdoMessage);
        }
        
        public bool ProcessMessage(CDO.Message cdoMessage)
        {
            try
            {
                this.Agent.ProcessMessage(cdoMessage);
                return true;
            }
            catch
            {
            }
            
            return false;
        }
        
        public bool ProcessIncomingMessage(CDO.Message cdoMessage)
        {
            try
            {
                this.Agent.ProcessIncoming(cdoMessage);
                return true;
            }
            catch
            {
            }
            
            return false;
        }
        
        public string ProcessIncoming(string messageText)
        {
            try
            {
                return this.Agent.ProcessIncoming(messageText);
            }
            catch
            {
            }
            
            return string.Empty;
        }
        
        public bool ProcessOutgoingMessage(CDO.Message message)
        {
            try
            {
                this.Agent.ProcessOutgoing(message);
                return true;
            }
            catch
            {
            }
            
            return false;
        }
        
        public string ProcessOutgoing(string messageText)
        {
            try
            {
                return this.Agent.ProcessOutgoing(messageText);
            }
            catch
            {
            }

            return string.Empty;
        }
        
        public CDO.Message CreateMessage(string text)
        {
            try
            {
                return this.Agent.CreateMessageFromText(text);
            }
            catch
            {
            }
            
            return null;
        }

        public string GetMessageSource(CDO.Message message)
        {
            try
            {
                return this.Agent.GetMessageSource(message);
            }
            catch
            {
            }
            
            return string.Empty;
        }
        
        public bool SetMessageSource(CDO.Message message, string text)
        {
            try
            {
                this.Agent.SetMessageSource(message, text);
                return true;
            }
            catch
            {
            }
            
            return false;
        }
        
        public void WriteLog(string message)
        {
            this.Agent.WriteLog(message);
        }
        
        public void WriteError(string message)
        {
            this.Agent.WriteError(message);
        }
        
        bool IsAgentInitialized(SmtpAgentImpl agent, string domain, string logFolderPath)
        {            
            return (agent != null 
                    && agent.Agent.Domain.Equals(domain, StringComparison.OrdinalIgnoreCase) 
                    && agent.Log.FolderPath.Equals(logFolderPath, StringComparison.OrdinalIgnoreCase));
        }
    }    
}
